对象-关系映射(Object/Relation Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的,是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术,本质上就是将数据从一种形式转换到另外一种形式。
面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将java程序中的对象自动持久化到关系数据库中,实现ORM的框架很多,其中当属Hibernate最为流行,下面通过几篇文章来看一下Hibernate是如何实现ORM的,即Hibernate的几种映射。
Hibernate在实现ORM功能的时候主要用到的文件有:
1、 映射类(*.java):它是描述数据库表的结构,表中的字段在类中被描述成属性,将来就可以实现把表中的记录映射成为该类的对象了。
2、映射文件(*.hbm.xml):它是指定数据库表和映射类之间的关系,包括映射类和数据库表的对应关系、表字段和类属性类型的对应关系以及表字段和类属性名称的对应关系等。
3、 hibernate核心配置文件(.properties/.cfg.xml):它指定hibernate的一些核心配置,包含与数据库连接时需要的连接信息,比如连接哪种数据库、登录数据库的用户名、登录密码以及连接字符串等。映射文件的地址信息也放在这里
基本映射
JPA方式映射
@Entity ,用于注解实体,通常无需指定属性。
@Table ,指定实体的表名。通过name属性来指定表名。
还可通过schema、catalog指定该表所在数据库Schema和Catalog。
uniqueConstrainter - 为表指定唯一约束。
@Id , 映射主键。
@Column : 映射列名。可指定name、length、scale、precision等属性
@GeneratedValue: 通过stragery指定主键生成策略。
@Transient: 用于标注某个属性,指定该属性不作为持久化属性,不映射到底层数据表。
为什么Hibernate的XML映射文件中没有与该Annotation对应的东西?
因为XML映射文件中不配置<property.../>,自动就不会作为持久化属性。
@Temporal: 专门用于修饰实体类的Date类型的属性。
默认情况下,java.util.Date类型的值既包含日期,也包含了时间。
但有些时候,数据列只要日期、或只要时间部分、或者是时间戳。
此时就需要使用@Temporal修饰。
@Enumerated: 修饰枚举类型的属性。
JPA简单示例User类:
@Entity
@Table(name="user")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String username;
private String password;
/**
* 专门用于修饰实体类的Date类型的属性。
* 默认情况下,java.util.Date类型的值既包含日期,也包含了时间。
* 但有些时候,数据列只要日期、或只要时间部分、或者是时间戳。
*/
@Temporal(TemporalType.DATE)
private Date birth;
private String imgurl;
/**
* 这儿表示这个filed是枚举类型
* EnumType.ORDINAL 表示的底层数据库保存的是枚举值的序号
* EnumType.STRING 表示的底层数据库保存的是枚举值的名称
* 这儿的Role是一个枚举类
*/
@Enumerated(EnumType.ORDINAL)
@Column(name="role_num")
private Role role;
/**
* 表示不想持久化保存这个Field
*/
@Transient
private String remark;
// getter 和 setter方法
}
XML方式映射
User.hibernate.xml配置文件如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="cn.xiaoyu.jpa.domain" table="user">
<id name="id" column="id" length="10" type="integer">
<!--
这儿的主键映射一般根据使用的数据库不同而是用不同的方案
mysql:increment sqlserver:indentity oracle:sequence
-->
<generator class="identity" />
</id>
<property name="username" length="50" />
<property name="password" length="50" />
<!-- 这儿type有date,datetime,timestamp三个类型 -->
<property name="birth" type="date" update="false" />
<property name="imgurl" length="50" />
<property name="role">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">cn.xiaoyu.jpa.domain.Role</param>
<!--
12为java.sql.Types.VARCHAR常量值,即保存枚举的字面值到数据库。
如果不指定type参数,保存枚举的索引值(从0开始)到数据库
默认是存的ordinal,也可指明4,即Integer。
-->
<param name="type">12</param>
</type>
</property>
</class>
</hibernate-mapping>
组件映射
JPA方式映射
映射复合类型的属性
在有些时候,实体属性的类型不是基本数据类型,也不是String,java.util.Date等简单类型,而是用户自定义的复合类型。
自定义的复合类型Cat类:
@Embeddable
public class Cat {
private String name;
private String color;
// getter 和 setter 方法
}
包含复合类型(Cat类)属性的Person实体类
@Entity
@Table(name="person")
@IdClass(Name.class)
public class Person {
@Id
private String first;
@Id
private String last;
// 组件映射
@Embedded
@AttributeOverrides({
@AttributeOverride(name="name"
,column=@Column(name="cat_name")),
@AttributeOverride(name="color"
,column=@Column(name="cat_color"))
})
private Cat cat;
// getter 和 setter 方法
}
在使用@Embeddable时不需要制定任何属性,而且Cat类不使用@Embeddable修饰也没有任何问题
映射实体类的主键
1.Person实体类和上面的实体类一样
public class Name {
private String first;
private String last;
// getter 和 setter 方法
}
这样使用@IdClass和@Id完成了实体内复合主键的映射
2.Name类和第一步中Name类一样
@Entity
@Table(name="person")
public class Person {
// 主键映射
@Embedded
@AttributeOverrides({
@AttributeOverride(name="first"
,column=@Column(name="first_name")),
@AttributeOverride(name="last"
,column=@Column(name="last_name"))
})
private Name name;
// 组件映射
@Embedded
@AttributeOverrides({
@AttributeOverride(name="name"
,column=@Column(name="cat_name")),
@AttributeOverride(name="color"
,column=@Column(name="cat_color"))
})
private Cat cat;
// getter 和 setter 方法
}
XML方式映射
映射复合类型的属性
<component name="name" class="Name">
<property name="first" />
<property name="last" />
</component>
映射主键的实体
<component-id name="name" class="Name">
<key-property name="first" />
<key-property name="last" />
</component-id>
集合映射
XML方式映射
List集合属性
private List<String> schools = new ArrayList<String>();
<!-- 映射List集合属性 -->
<list name="schools" table="school">
<key column="personid" not-null="true" />
<list-index column="list_order" />
<element type="string" column="school_name" />
</list>
数据库中会生成school表,personid和list_order共同作为school表中的联合主键
数组属性
private String[] schools;
<array name="schools" table="school">
<key column="personid" not-null="true" />
<list-index column="list_order" />
<element type="string" column="school_name" />
</array>
Set集合属性
private Set<String> schools = new HashSet<String>();
<set name="schools" table="school">
<key column="personid" not-null="true" />
<element type="string" column="school_name" not-null="true"/>
</set>
Collection集合属性
private Collection
Map集合属性
private Map<String,Float> scores = new HashMap<String,Float>();
<map name="scores" table="score">
<key column="personid" not-null="true" />
<map-key column="subject" type="string" />
<element type="float" column="grade" />
</map>